package com.ftpserver;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;


public class Client {
    private static final int FOUR=4;

    private ByteBuffer byteBuffer = ByteBuffer.allocate(4);
    private ByteBuffer byteFileLenBuffer = ByteBuffer.allocate(8);
    private ByteBuffer contextBuffer =  ByteBuffer.allocate(FileConfig.BUFFER_SIZE);

    /**
     * 文件名称
     */
    private String fileName;

    private int fileNameLen;

    private FileInputStream fis;

    private SocketChannel socketChannel;

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public FileInputStream getFis() {
        return fis;
    }

    public void setFis(FileInputStream fis) {
        this.fis = fis;
    }

    public SocketChannel getSocketChannel() {
        return socketChannel;
    }

    public void setSocketChannel(SocketChannel socketChannel) {
        this.socketChannel = socketChannel;
    }

    public FileChannel getFileChannel() {
        return fileChannel;
    }

    public void setFileChannel(FileChannel fileChannel) {
        this.fileChannel = fileChannel;
    }

    public long getFileLength() {
        return fileLength;
    }

    public void setFileLength(long fileLength) {
        this.fileLength = fileLength;
    }

    public long getRevicedLength() {
        return revicedLength;
    }

    public void setRevicedLength(long revicedLength) {
        this.revicedLength = revicedLength;
    }

    public FileTranStatus getFileTranStatus() {
        return fileTranStatus;
    }

    public void setFileTranStatus(FileTranStatus fileTranStatus) {
        this.fileTranStatus = fileTranStatus;
    }

    /**
     * 文件通道
     */
    private FileChannel fileChannel;

    /**
     * 文件大小
     */
    private long fileLength;

    /**
     * 收到文件大小
     */
    private long revicedLength;

    /**读取文件传输状态
     */
    private FileTranStatus fileTranStatus=FileTranStatus.FILE_NAME_LEN;


    public void close() {
        try {
            if(fileChannel!=null && fileChannel.isOpen())
                fileChannel.close();
            if(fis!=null )
                fis.close();
            if(socketChannel.isOpen()){
                Thread.sleep(2000);
                socketChannel.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     *获取文件channel
     */
    private  void getFilieChannel(){
        try {
            fis = new FileInputStream(FileConfig.FILE_PATH+fileName);
            fileChannel = fis.getChannel();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }


    public void read() throws Exception {
        if(fileTranStatus==FileTranStatus.FILE_NAME_LEN){
            //读取文件名称长度
            readFileNameLen();
            fileTranStatus=FileTranStatus.FILE_NAME;
        }else if(fileTranStatus==FileTranStatus.FILE_NAME){
            //读取文件内容长度
            readFileName();
            fileTranStatus=FileTranStatus.FILE_CONTENT_LEN;
        }else if(fileTranStatus==FileTranStatus.FILE_CONTENT_LEN){
            //读取文件内容
            readFileLen();
            fileTranStatus=FileTranStatus.FILE_CONTENT;
        }else if(fileTranStatus==FileTranStatus.FILE_CONTENT){
            //读取文件内容
            readContext();
            if(fileLength==revicedLength) {
                fileTranStatus = FileTranStatus.FILE_END;
            }
        }

    }

    /**
     * 读取文件内容
     * @return
     */
    private void readContext() throws  Exception {
        contextBuffer.clear();
        int len=socketChannel.read(contextBuffer);
        //已经读取的长度
        revicedLength+=len;
        if(len>0){
            contextBuffer.flip();
            while (contextBuffer.hasRemaining()) {
                fileChannel.write(contextBuffer);
            }
        }
        System.out.println("发送文件内容：总长度："+fileLength+",本次收到："+len+",已接收："+revicedLength);

    }

    /**
     * 文件名称一般没有多长，所以直接读取即可
     * @throws IOException
     */
    private void readFileName() throws IOException{
        ByteBuffer tmpByteBuffer = ByteBuffer.allocate(fileNameLen);
        while (tmpByteBuffer.hasRemaining() && socketChannel.read(tmpByteBuffer) > -1) ;
        byteBuffer.flip();
        fileName = new String(tmpByteBuffer.array(), Charset.forName("GBK"));

        System.out.println("文件名称："+fileName);
        //读取文件名称，直接打开文件
        fileChannel = new FileOutputStream(FileConfig.FILE_PATH+ File.separator+fileName).getChannel();
        tmpByteBuffer=null;
    }


    /**
     * 读取文件名称长度
     */
    private void readFileNameLen() throws IOException {
        byteBuffer.clear();
        //读取4个字节数据
        while (byteBuffer.hasRemaining() && socketChannel.read(byteBuffer) > -1) ;
        byteBuffer.flip();
        fileNameLen = byteBuffer.getInt();
    }


    /**
     * 读取文件名称长度
     */
    private void readFileLen() throws IOException {
        byteFileLenBuffer.clear();
        //读取4个字节数据
        while (byteFileLenBuffer.hasRemaining() && socketChannel.read(byteFileLenBuffer) > -1) ;
        byteFileLenBuffer.flip();
        fileLength = byteFileLenBuffer.getLong();
        byteFileLenBuffer =null;
    }




    public void write() throws Exception{
        if(fileTranStatus==FileTranStatus.FILE_CONTENT){
            byteBuffer.clear();
            byteBuffer.putInt(1);
            byteBuffer.flip();
            while(byteBuffer.hasRemaining() && socketChannel.write(byteBuffer)>-1);

        }else if(fileTranStatus==FileTranStatus.FILE_END){
            byteBuffer.clear();
            byteBuffer.putInt(2);
            byteBuffer.flip();
            while(byteBuffer.hasRemaining() && socketChannel.write(byteBuffer)>-1);
            System.out.println("服务端写完了..");
        }
    }
}

